#include <iostream>
#include <vector>
#include <assert.h>
#include <algorithm>
#include <cstring>

#define BUFFER_DEFAULT_SIZE 1024

class Buffer
{
private:
    std::vector<char> _buffer; // 内存空间管理
    uint64_t _read_idx;        // 读偏移
    uint64_t _write_idx;       // 写偏移

public:
    // 获取buffer起始地址
    char *Begin() { return (&*_buffer.begin()); } // 返回值不可以是void*，因为涉及了+-指针的操作，void*不可以+-
    // 将读偏移向后移动
    void MoveReadOffset(uint64_t len)
    {
        if(len == 0) return;
        assert(len <= ReadAbleSize());
        _read_idx += len;
    }
    // 将写偏移向后移动
    void MoveWirtePffset(uint64_t len)
    {
        assert(len <= TailIdleSize());
        _write_idx += len;
    }

    // 获取当前写入起始地址
    char *WritePosition() { return (Begin() + _write_idx); }
    // 获取当前读取起始地址
    char *ReadPosition() { return (Begin() + _read_idx); }
    // 获取缓冲区末尾空闲空间大小
    uint64_t TailIdleSize() { return _buffer.size() - _write_idx; }
    // 获取缓冲区开头空闲空间大小
    uint64_t HeadIdleSize() { return _read_idx; }
    // 寻找换行字符
    char *FindCRLF() { return (char *)memchr(ReadPosition(), '\n', ReadAbleSize()); }

public:
    Buffer()
        : _buffer(BUFFER_DEFAULT_SIZE), _read_idx(0), _write_idx(0) {}
    // 获取可读数据大小
    uint64_t ReadAbleSize() { return _write_idx - _read_idx; }
    // 确保可写空间足够（数据移动还是扩容问题）
    void EnsuerWriteSpace(uint64_t len)
    {
        // 末尾空闲空间足够
        if (TailIdleSize() >= len)
            return;
        // 末尾 + 起始空间足够，数据移动到起始位置
        if (len <= (TailIdleSize() + HeadIdleSize()))
        {
            // 把当前数据大小先保存起来
            uint64_t rsz = ReadAbleSize();
            std::copy(ReadPosition(), WritePosition(), (&*_buffer.begin()));
            _read_idx = 0;
            _write_idx = rsz;
        }
        // 总体空间不够，扩容
        else
        {
            std::cout << "扩容:" << _buffer.size() << std::endl;
            _buffer.resize(_write_idx + len);
        }
    }
    // 写入数据 + 更新写偏移
    void Write(void *data, uint64_t len)
    {
        // 保证空间足够
        EnsuerWriteSpace(len);
        // 拷贝数据
        const char *tmp = (const char *)data;
        std::copy(tmp, tmp + len, WritePosition());
        MoveWirtePffset(len);
    }
    // 写入string类型字符串
    void WriteString(const std::string &data) { Write((void *)data.c_str(), data.size()); }
    // 将另一个缓冲区内容写入
    void WirteBuffer(Buffer &data) { Write(data.ReadPosition(), data.ReadAbleSize()); }

    // 读取数据 + 更新读偏移
    void Read(void *buffer, uint64_t len)
    {
        // 因为提供了接口获取可读数据大小了，所以这里len必须是在可读数据大小之内
        assert(len <= ReadAbleSize());
        std::copy(ReadPosition(), ReadPosition() + len, (char *)buffer);
        MoveReadOffset(len);
    }
    std::string ReadString(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string buffer;
        buffer.resize(len);
        Read(&buffer[0], len);
        return buffer;
    }
    // 获取一行数据
    std::string GetLine()
    {
        char *pos = FindCRLF();
        if (pos == nullptr)
            return "";
        else
            return ReadString(pos - ReadPosition() + 1); // 把换行符也取出来
    }
    // 清空缓冲区
    void Clear()
    {
        _write_idx = _read_idx = 0;
    }
};

// copy是模板函数，需要保证前两个参数的类型统一才可以，而且都不能是void*
// template<class InputIterator, class OutputIterator>
//   OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
// {
//   while (first!=last) {
//     *result = *first;
//     ++result; ++first;
//   }
//   return result;
// }